/**
	https://github.com/datalog/datamatrix-svg
	under MIT license
	# datamatrix.js has no dependencies
	Copyright (c) 2020 Constantine
*/

/* eslint-disable */
'use strict';

function DATAMatrix(Q) {

	var M = []
		, xx = 0
		, yy = 0

		, bit = function (x, y) {

			M[y] = M[y] || [],
				M[y][x] = 1;
		}

		, toAscii = function (t) {

			var
				r = [],
				l = t.length;

			for (var i = 0; i < l; i++) {

				var
					c = t.charCodeAt(i),
					c1 = (i + 1 < l) ? t.charCodeAt(i + 1) : 0;

				if (c > 47 && c < 58 && c1 > 47 && c1 < 58) { /* 2 digits */

					r.push((c - 48) * 10 + c1 + 82), /* - 48 + 130 = 82 */
						i++;

				} else if (c > 127) { /* extended char */

					r.push(235),
						r.push((c - 127) & 255);

				} else r.push(c + 1); /* char */
			}

			return r;
		}

		, toBase = function (t) {

			var
				r = [231], /* switch to Base 256 */
				l = t.length;

			if (250 < l) {

				r.push(37 + (l / 250 | 0) & 255); /* length high byte (in 255 state algo) */
			}

			r.push(l % 250 + 149 * (r.length + 1) % 255 + 1 & 255); /* length low byte (in 255 state algo) */

			for (var i = 0; i < l; i++) {

				r.push(t.charCodeAt(i) + 149 * (r.length + 1) % 255 + 1 & 255); /* data in 255 state algo */
			}

			return r;
		}

		, toEdifact = function (t) {

			var
				n = t.length,
				l = (n + 1) & -4, cw = 0, ch,
				r = (l > 0) ? [240] : []; /* switch to Edifact */

			for (var i = 0; i < l; i++) {

				if (i < l - 1) {

					/* encode char */
					ch = t.charCodeAt(i);
					if (ch < 32 || ch > 94) return []; /* not in set */

				} else ch = 31; /* return to ASCII */

				cw = cw * 64 + (ch & 63);

				if ((i & 3) == 3) {

					/* 4 data in 3 words */
					r.push(cw >> 16),
						r.push(cw >> 8 & 255),
						r.push(cw & 255),
						cw = 0;
				}
			};

			return l > n ? r : r.concat(toAscii(t.substr(l == 0 ? 0 : l - 1))); /* last chars*/
		}

		, toText = function (t, s) {

			var
				i, j,
				cc = 0,
				cw = 0,
				l = t.length,
				r = [s[0]], /* start switch */
				push = function (v) {

					/* pack 3 chars in 2 codes */
					cw = 40 * cw + v;

					/* add code */
					if (cc++ == 2) {

						r.push(++cw >> 8),
							r.push(cw & 255),
							cc = cw = 0;
					}
				};

			for (i = 0; i < l; i++) {

				/* last char in ASCII is shorter */
				if (0 == cc && i == l - 1) break;

				var
					ch = t.charCodeAt(i);

				if (ch > 127 && 238 != r[0]) { /* extended char */

					push(1),
						push(30),
						ch -= 128; /* hi bit in C40 & TEXT */
				}

				for (j = 1; ch > s[j]; j += 3); /* select char set */

				var
					x = s[j + 1]; /* shift */


				if (8 == x || (9 == x && 0 == cc && i == l - 1)) return []; /* char not in set or padding fails */

				if (x < 5 && cc == 2 && i == l - 1) break; /* last char in ASCII */
				if (x < 5) push(x); /* shift */

				push(ch - s[j + 2]); /* char offset */
			}

			if (2 == cc && 238 !== r[0]) { /* add pad */

				push(0);
			}

			r.push(254); /* return to ASCII */

			if (cc > 0 || i < l) r = r.concat(toAscii(t.substr(i - cc))); /* last chars */

			return r;
		}

		, encodeMsg = function (text, rct) {

			text = unescape(encodeURI(text));

			var M = [];

			var
				enc = toAscii(text),
				el = enc.length,

				k = toText(text, [	/* C40 */
					230,
					31, 0, 0,
					32, 9, 29,
					47, 1, 33,
					57, 9, 44,
					64, 1, 43,
					90, 9, 51,
					95, 1, 69,
					127, 2, 96,
					255, 1, 0
				]),
				l = k.length;
			if (l > 0 && l < el) enc = k, el = l;


			k = toText(text, [	/* TEXT */
				239,
				31, 0, 0,
				32, 9, 29,
				47, 1, 33,
				57, 9, 44,
				64, 1, 43,
				90, 2, 64,
				95, 1, 69,
				122, 9, 83,
				127, 2, 96,
				255, 1, 0
			]);
			l = k.length;
			if (l > 0 && l < el) enc = k, el = l;

			k = toText(text, [	/* X12*/
				238,
				12, 8, 0,
				13, 9, 13,
				31, 8, 0,
				32, 9, 29,
				41, 8, 0,
				42, 9, 41,
				47, 8, 0,
				57, 9, 44,
				64, 8, 0,
				90, 9, 51,
				255, 8, 0
			]);
			l = k.length;
			if (l > 0 && l < el) enc = k, el = l;

			k = toEdifact(text); l = k.length;
			if (l > 0 && l < el) enc = k, el = l;

			k = toBase(text); l = k.length;
			if (l > 0 && l < el) enc = k, el = l;


			var
				h, w, nc = 1, nr = 1, fw, fh, /* symbol size, regions, region size */
				i, j = - 1, c, r, s, b = 1, /* compute symbol size */

				rs = new Array(70), /* reed / solomon code */
				rc = new Array(70),
				lg = new Array(256), /* log / exp table for multiplication */
				ex = new Array(255);

			if (rct && el < 50) {

				/* rect */

				k = [	/* symbol width, checkwords */
					16, 7,
					28, 11,
					24, 14,
					32, 18,
					32, 24,
					44, 28
				];

				do {
					w = k[++j]; /* width */
					h = 6 + (j & 12); /* height */
					l = w * h / 8; /* bytes count in symbol */

				} while (l - k[++j] < el); /* could we fill the rect? */

				/* column regions */
				if (w > 25) nc = 2;

			} else {

				/* square */

				w = h = 6;
				i = 2; /* size increment */
				k = [5, 7, 10, 12, 14, 18, 20, 24, 28, 36, 42, 48, 56, 68, 84, 112, 144, 192, 224, 272, 336, 408, 496, 620]; /* rs checkwords */

				do {
					if (++j == k.length) return [0, 0]; /* msg is too long */

					if (w > 11 * i) i = 4 + i & 12; /* advance increment */

					w = h += i;
					l = (w * h) >> 3;

				} while (l - k[j] < el);

				if (w > 27) nr = nc = 2 * (w / 54 | 0) + 2; /* regions */
				if (l > 255) b = 2 * (l >> 9) + 2; /* blocks */
			}


			s = k[j], /* rs checkwords */
				fw = w / nc, /* region size */
				fh = h / nr;

			/* first padding */
			if (el < l - s) enc[el++] = 129;

			/* more padding */
			while (el < l - s) {

				enc[el++] = (((149 * el) % 253) + 130) % 254;
			}


			/* Reed Solomon error detection and correction */
			s /= b;

			/* log / exp table of Galois field */
			for (j = 1, i = 0; i < 255; i++) {

				ex[i] = j,
					lg[j] = i,
					j += j;

				if (j > 255) j ^= 301; /* 301 == a^8 + a^5 + a^3 + a^2 + 1 */
			}

			/* RS generator polynomial */
			for (rs[s] = 0, i = 1; i <= s; i++)
				for (j = s - i, rs[j] = 1; j < s; j++)
					rs[j] = rs[j + 1] ^ ex[(lg[rs[j]] + i) % 255];

			/* RS correction data for each block */
			for (c = 0; c < b; c++) {
				for (i = 0; i <= s; i++) rc[i] = 0;
				for (i = c; i < el; i += b)
					for (j = 0, x = rc[0] ^ enc[i]; j < s; j++)
						rc[j] = rc[j + 1] ^ (x ? ex[(lg[rs[j]] + lg[x]) % 255] : 0);

				/* interleaved correction data */
				for (i = 0; i < s; i++)
					enc[el + c + i * b] = rc[i];
			}

			/* layout perimeter finder pattern */
			/* horizontal */
			for (i = 0; i < h + 2 * nr; i += fh + 2)
				for (j = 0; j < w + 2 * nc; j++) {
					bit(j, i + fh + 1);
					if ((j & 1) == 0) bit(j, i);
				}

			/* vertical */
			for (i = 0; i < w + 2 * nc; i += fw + 2)
				for (j = 0; j < h; j++) {
					bit(i, j + (j / fh | 0) * 2 + 1);
					if ((j & 1) == 1) bit(i + fw + 1, j + (j / fh | 0) * 2);
				}

			s = 2, /* step */
				c = 0, /* column */
				r = 4, /* row */
				b = [ /* nominal byte layout */
					0, 0,
					-1, 0,
					-2, 0,
					0, -1,
					-1, -1,
					-2, -1,
					-1, -2,
					-2, -2
				];

			/* diagonal steps */
			for (i = 0; i < l; r -= s, c += s) {

				if (r == h - 3 && c == - 1)

					k = [ /* corner A layout */
						w, 6 - h,
						w, 5 - h,
						w, 4 - h,
						w, 3 - h,
						w - 1, 3 - h,
						3, 2,
						2, 2,
						1, 2
					];

				else if (r == h + 1 && c == 1 && (w & 7) == 0 && (h & 7) == 6)

					k = [ /* corner D layout */
						w - 2, -h,
						w - 3, -h,
						w - 4, -h,
						w - 2, -1 - h,
						w - 3, -1 - h,
						w - 4, -1 - h,
						w - 2, -2,
						-1, -2
					];
				else {
					if (r == 0 && c == w - 2 && (w & 3)) continue; /* corner B: omit upper left */
					if (r < 0 || c >= w || r >= h || c < 0) { /* outside */

						s = -s, /* turn around */
							r += 2 + s / 2,
							c += 2 - s / 2;

						while (r < 0 || c >= w || r >= h || c < 0) {

							r -= s,
								c += s;
						}
					}
					if (r == h - 2 && c == 0 && (w & 3))

						k = [ /* corner B layout */
							w - 1, 3 - h,
							w - 1, 2 - h,
							w - 2, 2 - h,
							w - 3, 2 - h,
							w - 4, 2 - h,
							0, 1,
							0, 0,
							0, -1
						];

					else if (r == h - 2 && c == 0 && (w & 7) == 4)

						k = [ /* corner C layout */
							w - 1, 5 - h,
							w - 1, 4 - h,
							w - 1, 3 - h,
							w - 1, 2 - h,
							w - 2, 2 - h,
							0, 1,
							0, 0,
							0, -1
						];

					else if (r == 1 && c == w - 1 && (w & 7) == 0 && (h & 7) == 6) continue; /* omit corner D */
					else k = b; /* nominal L - shape layout */
				}

				/* layout each bit */
				for (el = enc[i++], j = 0; el > 0; j += 2, el >>= 1) {

					if (el & 1) {

						var
							x = c + k[j],
							y = r + k[j + 1];

						/* wrap around */
						if (x < 0) x += w, y += 4 - ((w + 4) & 7);
						if (y < 0) y += h, x += 4 - ((h + 4) & 7);

						/* region gap */
						bit(x + 2 * (x / fw | 0) + 1, y + 2 * (y / fh | 0) + 1);
					}
				}
			}



			/* unfilled corner */
			for (i = w; i & 3; i--) {

				bit(i, i);
			}

			xx = w + 2 * nc,
				yy = h + 2 * nr;
		}

	return (function () {

		function ishex(c) {

			return /^#[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(c);
		}

		function svg(n, a) {

			n = document.createElementNS(ns, n);

			for (var o in a || {}) {

				n.setAttribute(o, a[o]);
			}

			return n;
		}

		var
			abs = Math.abs,
			r, x, y, d, sx, sy,

			ns = 'http://www.w3.org/2000/svg',
			path = '',

			q = ('string' == typeof Q) ? { msg: Q } : Q || {},
			p = q.pal || ['#000'],
			dm = abs(q.dim) || 256,
			pd = abs(q.pad), pd = (pd > -1) ? pd : 2,
			mx = [1, 0, 0, 1, pd, pd],

			fg = p[0], fg = ishex(fg) ? fg : '#000',
			bg = p[1], bg = ishex(bg) ? bg : 0,

			/* render optimized or verbose svg */
			optimized = (q.vrb) ? 0 : 1;

		encodeMsg(q.msg || '', q.rct);

		sx = xx + pd * 2,
			sy = yy + pd * 2;

		y = yy;

		while (y--) {

			d = 0, x = xx;

			while (x--) {

				if (M[y][x]) {

					if (optimized) {

						d++;

						if (!M[y][x - 1])

							path += 'M' + x + ',' + y + 'h' + d + 'v1h-' + d + 'v-1z', d = 0;

					} else path += 'M' + x + ',' + y + 'h1v1h-1v-1z';
				}
			}
		}


		r = svg('svg', {

			'viewBox': [0, 0, sx, sy].join(' ')
			, 'width': dm / sy * sx | 0
			, 'height': dm
			, 'fill': fg
			, 'shape-rendering': 'crispEdges'
			, 'xmlns': ns
			, 'version': '1.1'
		});

		if (bg) r.appendChild(svg('path', {

			'fill': bg
			, 'd': 'M0,0v' + sy + 'h' + sx + 'V0H0Z'
		}));

		r.appendChild(svg('path', {

			'transform': 'matrix(' + mx + ')'
			, 'd': path
		}));

		return r;

	})();
}

export default DATAMatrix